﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using _5E.Infrastructure.Querying;
using Melee.Contract;
using Melee.DataContract.Extension;
using Melee.DataContract.Messaging;
using Melee.DataContract.Views;
using Melee.Infrastructure.Configuration;
using Melee.Models.Entity;
using Melee.Models.Repository;

namespace Melee.Service.Services
{
    public class GameService : IGameService
    {
        private IMapRepository m_mapRepository = null;
        private ICityRepository m_cityRepository = null;
        private IAreaRepository m_areaRepository = null;
        private IPlayerRepository m_playerRepository = null;

        public GameService(IMapRepository mapRepositiry, ICityRepository cityRepository, IAreaRepository areaRepository,
            IPlayerRepository playerRepository)
        {
            m_mapRepository = mapRepositiry;
            m_cityRepository = cityRepository;
            m_areaRepository = areaRepository;
            m_playerRepository = playerRepository;
        }

        public GetInitializationDataResponse GetInitializationDataBy(GetInitializationDataRequest request)
        {
            GetInitializationDataResponse response = new GetInitializationDataResponse();
            try
            {
                InitializationView view = new InitializationView();

                view.Images = FindImgSources();

                view.Config = GetConfigViewBy(request);

                Query mapQuery = new Query();
                mapQuery.AddOrder<Map>(m => m.Y);
                mapQuery.AddOrder<Map>(m => m.X);
                view.Maps = m_mapRepository.FindBy(mapQuery).ConvertToMapView();

                Query mainCityQuery = new Query();
                mainCityQuery.Add<City>(c => c.PlayerId, CriteriaOperator.Eq, request.LoginId);
                City mainCity = m_cityRepository.FindBy(mainCityQuery).First();
                view.MainCityX = mainCity.StartingPoint.X * ApplicationSettingsFactory.ApplicationSettings.PointLength;
                view.MainCityY = mainCity.StartingPoint.Y * ApplicationSettingsFactory.ApplicationSettings.PointLength;
                view.MainCityWidth = mainCity.Level.Width * ApplicationSettingsFactory.ApplicationSettings.PointLength;
                view.MainCityHeight = mainCity.Level.Height * ApplicationSettingsFactory.ApplicationSettings.PointLength;

                view.Player = m_playerRepository.FindBy(request.LoginId).ConvertToPlayerView();

                response.InitializationData = view;
            }
            catch (Exception ex)
            {
                response.Message = "加载初始化数据失败!";
                response.Success = false;
                response.Exception = ex;
            }
            return response;
        }

        private ConfigView GetConfigViewBy(GetInitializationDataRequest request)
        {
            Int32[] maxPositions = m_areaRepository.FindMaxXAndMaxY();
            ConfigView config = new ConfigView
            {
                AreaLength = ApplicationSettingsFactory.ApplicationSettings.AreaLength,
                PointLength = ApplicationSettingsFactory.ApplicationSettings.PointLength,
                Width = request.WindowWidth < ApplicationSettingsFactory.ApplicationSettings.InterfaceWidth ?
                    ApplicationSettingsFactory.ApplicationSettings.InterfaceWidth : request.WindowWidth,
                MaxWidth = ApplicationSettingsFactory.ApplicationSettings.AreaLength * (maxPositions[0] + 1),
                Height = request.WindowHeight < ApplicationSettingsFactory.ApplicationSettings.InterfaceHeight ?
                    ApplicationSettingsFactory.ApplicationSettings.InterfaceHeight : request.WindowHeight,
                MaxHeight = ApplicationSettingsFactory.ApplicationSettings.AreaLength * (maxPositions[1] + 1),
                MapWidth = ApplicationSettingsFactory.ApplicationSettings.MapWidth,
                MapHeight = ApplicationSettingsFactory.ApplicationSettings.MapHeight
            };
            return config;
        }

        private IEnumerable<string> FindImgSources()
        {
            IList<string> imgPaths = new List<string>();
            DirectoryInfo baseDir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory +
                ApplicationSettingsFactory.ApplicationSettings.ImageBaseDir);
            foreach (DirectoryInfo dir in baseDir.GetDirectories())
            {
                if (-1 == ApplicationSettingsFactory.ApplicationSettings.ImageFileNames.IndexOf(dir.Name))
                    continue;

                AddImagePath(imgPaths, dir);
            }
            return imgPaths;
        }

        private void AddImagePath(IList<string> imgPaths, DirectoryInfo dir)
        {
            DirectoryInfo[] childDirs = dir.GetDirectories();
            if (0 < childDirs.Length)
            {
                foreach (DirectoryInfo childDir in childDirs)
                {
                    AddImagePath(imgPaths, childDir);
                }
            }
            else
            {
                foreach (FileInfo file in dir.GetFiles())
                {
                    if (-1 == ApplicationSettingsFactory.ApplicationSettings.ImageExtensions.IndexOf(file.Extension))
                        continue;

                    imgPaths.Add(file.FullName.Replace(AppDomain.CurrentDomain.BaseDirectory, string.Empty));
                }
            }
        }
    }
}
